// Created: Dec 14, 2014
//
// Author: wjinwen.1988@gmail.com

#include "chi/net/tls_server.h"

#include <stdio.h>
#include <assert.h>

#include <functional>

#include <glog/logging.h>

#include "chi/net/acceptor.h"
#include "chi/net/event_loop.h"
#include "chi/net/event_loop_thread_pool.h"

namespace chi {
namespace net {

using namespace std::placeholders;

TLSServer::TLSServer(SSL_CTX* ssl_ctx,
                     EventLoop* loop,
                     const InetAddress& listenaddr,
                     const std::string& name) 
  : TcpServer(loop, listenaddr, name),
    ssl_ctx_(ssl_ctx) {
}

TLSServer::~TLSServer() {
}

void TLSServer::NewConnection(int sockfd, const InetAddress& peeraddr) {
  SSL* ssl = SSL_new(ssl_ctx_);
  assert(ssl != nullptr);
  
  EventLoop* io_loop = thread_pool_->GetNextLoop();
  char buf[32];
  snprintf(buf, sizeof(buf), ":%s#%d", hostport_.c_str(), next_connid_);
  ++next_connid_;
  std::string conn_name = name_+buf;

  LOG(INFO) << "[" << name_ << "] - new connection [" << conn_name 
            << "] - from " << peeraddr.ToIpPort();
  InetAddress localaddr(Socket::GetLocalAddr(sockfd));
  TLSConnectionPtr conn(new TLSConnection(ssl,
                                          io_loop,
                                          conn_name,
                                          sockfd,
                                          localaddr,
                                          peeraddr)); 
  connections_[conn_name] = conn;
  conn->set_connection_callback(connection_callback_);
  conn->set_message_callback(message_callback_);
  conn->set_close_callback(
      std::bind(&TLSServer::RemoveConnection, this, _1));
  // Start TLS accept in loop.
  io_loop->RunInLoop(std::bind(&TLSConnection::SSLAccept, conn));
}

}  
}
